#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/11/13 10:49
# @Author  : Yunhao.Cao
# @File    : proxy.py
from __future__ import absolute_import, unicode_literals
import datetime
import json
import random
import multiprocessing
from logger import Logger

__author__ = 'Yunhao.Cao'

__ALL__ = ["ProxyManager", ]


class Proxy:
    def __init__(self):
        pass

    ip = str()
    fail_time = int()
    last_call_time = datetime.datetime.now()


class ProxyManager:
    def __init__(self, file_path):
        """
        初始化，解析json文件
        :param file_path:
        :return:
        """
        with open(file_path) as json_file:
            data = json.load(json_file, encoding="gbk")
        proxy_list = data["data"]

        # 为每个proxy单位增加字段
        if proxy_list:
            def _add_fields(proxy):
                proxy["fail_time"] = 0

            map(_add_fields, proxy_list)

        self._proxy_list = proxy_list
        _manager = multiprocessing.Manager()
        self._lock = _manager.Lock()

    def get(self):
        """
        获取一个'失败次数最少'的代理
        :return:
        """
        self._acquire()
        try:
            if self._proxy_list:
                proxy = self._get_sorted_proxy_list()[0]
                Logger.info("Get Proxy. ({})".format(proxy))
                return self._to_proxy_ip(proxy)
        finally:
            self._release()

    def add_fail_times(self, proxy_ip, **kwargs):
        """
        增加一个代理的失败次数
        :param proxy_ip: 代理ip
        :param kwargs: 其他参数
        :return:
        """
        self._acquire()
        try:
            if not proxy_ip:
                Logger.warning("proxy_ip is Empty.")
                return
            context = kwargs.get("context")
            proxy = self._get_proxy(proxy_ip.split(":")[0])
            if proxy:
                proxy["fail_time"] += 1
            Logger.warning("fail proxy = {}.({})".format(proxy, context))
        finally:
            self._release()

    def get_random(self):
        """
        随机获取一个代理
        :return:
        """
        self._acquire()
        try:
            return self._to_proxy_ip(self._proxy_list[int(random.random() * len(self._proxy_list))])
        finally:
            self._release()

    def _get_sorted_proxy_list(self):
        self._proxy_list = sorted(self._proxy_list, lambda a, b: cmp(a["fail_time"], b["fail_time"]))
        return self._proxy_list

    def _get_proxy(self, ip):
        if ip:
            for proxy in self._proxy_list:
                if ip == proxy["ip"]:
                    return proxy
        return None

    def _acquire(self, *args, **kwargs):
        if self._lock:
            self._lock.acquire(*args, **kwargs)

    def _release(self, *args, **kwargs):
        if self._lock:
            self._lock.release(*args, **kwargs)

    @staticmethod
    def _to_proxy_ip(proxy):
        return "{}:{}".format(proxy["ip"], proxy["port"]) if proxy else None


if __name__ == '__main__':
    pm = ProxyManager("./proxy.json")
    print(pm.get_random())
